#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h>
#define name_len 30
#define buff_size 100

DWORD WINAPI send_msg(LPVOID lpParam);
DWORD WINAPI recv_msg(LPVOID lpParam);
char name[name_len];
char sendmsg[buff_size];
char recvmsg[buff_size+name_len+3];
HANDLE htread[2];
void error_handling(const char *msg);

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(void) {
    WSADATA wsa_data;
    WSAStartup(MAKEWORD(2,2),&wsa_data);
    printf("your name:");
    fgets(name, name_len, stdin);
    if (name[strlen(name) - 1] == '\n') {
        name[strlen(name) - 1] = '\0';
    }
    SOCKET clnt_socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(clnt_socket==INVALID_SOCKET){
        error_handling("socket creation failed\n");
    }
    struct sockaddr_in server_addr;
    server_addr.sin_family=AF_INET;
    server_addr.sin_port=htons(8080);
    server_addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
    if(connect(clnt_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))==SOCKET_ERROR){
        error_handling("connection failed\n");
    }
    printf("connection established\n");
    DWORD send_thread_id;
    DWORD recv_thread_id;
    htread[0]=CreateThread(NULL,0,send_msg,&clnt_socket,0,&send_thread_id);
    htread[1]=CreateThread(NULL,0,recv_msg,&clnt_socket,0,&recv_thread_id);
    WaitForMultipleObjects(2,htread,TRUE,INFINITE);
    CloseHandle(htread[0]);
    CloseHandle(htread[1]);
    printf("threads terminated\n");
    getchar();
    closesocket(clnt_socket);
    WSACleanup();
    return 0;
}

DWORD WINAPI send_msg(LPVOID lpParam) {
    int sock = *((int*)lpParam);
    while (1) {
        fgets(sendmsg, buff_size, stdin);
        size_t len = strlen(sendmsg);
        if (len > 0 && sendmsg[len - 1] == '\n') {
            sendmsg[len - 1] = '\0';
        }
        int name_size = strlen(name);
        char* send_msg1 = (char*)malloc(name_size + buff_size + 3);
        if (send_msg1 == NULL) {
            error_handling("memory allocation failed\n");
            continue; 
        }
        snprintf(send_msg1, "[%s]: %s", name, sendmsg);
        int a = send(sock, send_msg1, strlen(send_msg1), 0);
        if (a == SOCKET_ERROR) {
            error_handling("send failed\n");
        }
        free(send_msg1);
    }
    return 0;
}

DWORD WINAPI recv_msg(LPVOID lpParam) {
    int sock = (*(int*)lpParam);
    while (1) {
        int recv_len = recvfrom(sock, recvmsg, sizeof(recvmsg) - 1, 0, NULL, NULL);
        if (recv_len == SOCKET_ERROR) {
            error_handling("receive failed\n");
        }
        recvmsg[recv_len] = '\0';
        fputs(recvmsg, stdout);
    }
    return 0;
}

void error_handling(const char *msg){
    printf("%s",msg);

    WSACleanup();
    exit(1);
}
